
#include "kernel/nkernelserver.h"
#include "kernel/ntimeserver.h"
#include "python/npythonserver.h"
#include "application/napplication.h"
#include "scene/nsceneserver.h"
#include "variable/nvariableserver.h"
#include "nanachronox/ngamestate.h"

nNebulaClass(nGameState, "nappstate");

//------------------------------------------------------------------------------
/**
*/
nGameState::nGameState() :
	// variable initialisation
	frameId(0)
{
    // empty
}

//------------------------------------------------------------------------------
/**
*/
void
nGameState::OnStateEnter(const nString& prevState)
{
	nPythonServer* scriptServer = nPythonServer::Instance;
	nString scriptResult;
	scriptServer->RunFunction("OnGameEntered", scriptResult);
    n_printf("nAppState::OnStateEnter(%s) called.. on state %s\n", prevState.Get(), this->GetName());

	if (!this->refRootNode.isvalid())
    {
        this->refRootNode = (nTransformNode*) kernelServer->Lookup("/usr/scene");
        n_assert(this->refRootNode.isvalid());
 
		nVariableServer *varServer = nVariableServer::Instance();
		static const nFloat4 wind = { 1.0f, 0.0f, 0.0f, 0.5f };
        nVariable::Handle timeHandle = varServer->GetVariableHandleByName("time");
        nVariable::Handle oneHandle  = varServer->GetVariableHandleByName("one");
        nVariable::Handle windHandle = varServer->GetVariableHandleByName("wind");
        this->renderContext.AddVariable(nVariable(timeHandle, 0.5f));
        this->renderContext.AddVariable(nVariable(oneHandle, 1.0f));
        this->renderContext.AddVariable(nVariable(windHandle, wind));
        this->renderContext.SetRootNode(this->refRootNode.get());
        this->refRootNode->RenderContextCreated(&this->renderContext);
    }
}

//------------------------------------------------------------------------------
/**
*/
void
nGameState::OnFrame()
{
	nVariableServer *varServer = nVariableServer::Instance();
	nKernelServer *kernelServer = nKernelServer::Instance();
    nVariable::Handle timeHandle = varServer->GetVariableHandleByName("time");
    nTime time = kernelServer->GetTimeServer()->GetTime();
    this->renderContext.GetVariable(timeHandle)->SetFloat((float)time);
    this->TransferGlobalVariables();
    this->renderContext.SetFrameId(this->frameId++);
}

//------------------------------------------------------------------------------
/**
*/
void
nGameState::OnRender3D()
{
	nSceneServer* sceneServer = nSceneServer::Instance();
	sceneServer->Attach(&this->renderContext);
}

//------------------------------------------------------------------------------
/**
*/
void
nGameState::OnRender2D()
{
    // n_printf("nGameState::OnRender2D() called on state %s\n", this->GetName());
}

//------------------------------------------------------------------------------
/**
    Transfer global variables from the variable server to the
    render context.
*/
void
nGameState::TransferGlobalVariables()
{
	nVariableServer *varServer = nVariableServer::Instance();
    const nVariableContext& globalContext = varServer->GetGlobalVariableContext();
    int numGlobalVars = globalContext.GetNumVariables();
    int globalVarIndex;
    for (globalVarIndex = 0; globalVarIndex < numGlobalVars; globalVarIndex++)
    {
        const nVariable& globalVar = globalContext.GetVariableAt(globalVarIndex);
        nVariable* var = this->renderContext.GetVariable(globalVar.GetHandle());
        if (var)
        {
            *var = globalVar;
        }
        else
        {
            nVariable newVar(globalVar);
            this->renderContext.AddVariable(newVar);
        }
    }
}
